home *** CD-ROM | disk | FTP | other *** search
/ PCGUIA 127 / PC Guia 127.iso / Software / Utils / Forecastfox / Bin / forecastfox-0.8.5.1-fx+mz+ns.xpi / components / ffIconManager.js < prev    next >
Encoding:
Text File  |  2006-02-18  |  31.4 KB  |  931 lines

  1. /* ***** BEGIN LICENSE BLOCK *****
  2.  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
  3.  *
  4.  * The contents of this file are subject to the Mozilla Public License Version
  5.  * 1.1 (the "License"); you may not use this file except in compliance with
  6.  * the License. You may obtain a copy of the License at
  7.  * http://www.mozilla.org/MPL/
  8.  *
  9.  * Software distributed under the License is distributed on an "AS IS" basis,
  10.  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
  11.  * for the specific language governing rights and limitations under the
  12.  * License.
  13.  *
  14.  * The Original Code is Forecastfox.
  15.  *
  16.  * The Initial Developer of the Original Code is
  17.  * Jon Stritar <jstritar@MIT.EDU>.
  18.  * Portions created by the Initial Developer are Copyright (C) 2005
  19.  * the Initial Developer. All Rights Reserved.
  20.  *
  21.  * Contributor(s):
  22.  * Jon Stritar <jstritar@MIT.EDU>
  23.  * Richard Klein <richwklein@mchsi.com>
  24.  *
  25.  * Alternatively, the contents of this file may be used under the terms of
  26.  * either the GNU General Public License Version 2 or later (the "GPL"), or
  27.  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
  28.  * in which case the provisions of the GPL or the LGPL are applicable instead
  29.  * of those above. If you wish to allow use of your version of this file only
  30.  * under the terms of either the GPL or the LGPL, and not to allow others to
  31.  * use your version of this file under the terms of the MPL, indicate your
  32.  * decision by deleting the provisions above and replace them with the notice
  33.  * and other provisions required by the GPL or the LGPL. If you do not delete
  34.  * the provisions above, a recipient may use your version of this file under
  35.  * the terms of any one of the MPL, the GPL or the LGPL.
  36.  *
  37.  * ***** END LICENSE BLOCK ***** */
  38.  
  39. const MANAGER_CLASS_ID = Components.ID("{5158b980-0a0e-11da-8cd6-0800200c9a66}");
  40. const MANAGER_CLASS_NAME = "Forecastfox Icon Manager Component";
  41. const MANAGER_CONTRACT_ID = "@ensolis.com/forecastfox/icon-manager;1";
  42. const INSTALLER_CLASS_ID = Components.ID("{f81ad500-24cb-11da-8cd6-0800200c9a66}");
  43. const INSTALLER_CLASS_NAME = "Forecastfox Icon Pack Installer";
  44. const INSTALLER_CONTRACT_ID = "@ensolis.com/forecastfox/icon-installer;1";
  45.  
  46. const IM_PREFIX = "http://www.ensolis.com/2005/icon-manager#";
  47. const ICON_PREFIX = "http://www.ensolis.com/2005/icon-pack/";
  48. const ICONS_ROOT = "urn:ensolis:icon-packs:root";
  49. const ffIIconManager = Components.interfaces.ffIIconManager;
  50. const ffIError = Components.interfaces.ffIError;
  51. const ffIDisk = Components.interfaces.ffIDisk;
  52. const nsIFile = Components.interfaces.nsIFile;
  53.  
  54. const REQUIRED_PACK_FILES = ["pack.rdf", "small/01.png", "small/02.png", "small/03.png", "small/04.png",
  55.        "small/05.png", "small/06.png", "small/07.png", "small/08.png", "small/11.png", "small/12.png", "small/13.png", "small/14.png", "small/15.png",
  56.        "small/16.png", "small/17.png", "small/18.png", "small/19.png", "small/20.png", "small/21.png", "small/22.png", "small/23.png", "small/24.png",
  57.        "small/25.png", "small/26.png", "small/29.png", "small/30.png", "small/31.png", "small/32.png", "small/33.png", "small/34.png", "small/35.png",
  58.        "small/36.png", "small/37.png", "small/38.png", "small/39.png", "small/40.png", "small/41.png", "small/42.png", "small/43.png", "small/44.png",
  59.        "small/radar.png", "small/swa.png", "large/01.png", "large/02.png", "large/03.png", "large/04.png", "large/05.png", "large/06.png", "large/07.png",
  60.        "large/08.png", "large/11.png", "large/12.png", "large/13.png", "large/14.png", "large/15.png", "large/16.png", "large/17.png", "large/18.png",
  61.        "large/19.png", "large/20.png", "large/21.png", "large/22.png", "large/23.png", "large/24.png", "large/25.png", "large/26.png", "large/29.png",
  62.        "large/30.png", "large/31.png", "large/32.png", "large/33.png", "large/34.png", "large/35.png", "large/36.png", "large/37.png", "large/38.png",
  63.        "large/39.png", "large/40.png", "large/41.png", "large/42.png", "large/43.png", "large/44.png", "large/swa.png"];
  64.        
  65. const REQUIRED_ICON_PROPS = ["id", "name", "version", "website", "author", "target", "smallWidth", "smallHeight", "largeWidth", "largeHeight"];
  66.  
  67. function ffIconManager() {};
  68.  
  69. ffIconManager.prototype = {
  70.   _manager: null,
  71.   _rdfserv: null,
  72.   _ds: null,
  73.   _bundle: null,
  74.   _obs: null,
  75.   _current: null,
  76.   
  77.   get datasource() {
  78.     if (!this._ds)
  79.       this._getRdf(false);
  80.     
  81.     return this._ds;
  82.   },
  83.   
  84.   get current() { return this._current; },
  85.   
  86.   start: function()
  87.   {
  88.     this._manager = Components.classes["@ensolis.com/forecastfox/manager;1"].getService(Components.interfaces.ffIManager);
  89.     this._rdfserv = Components.classes["@mozilla.org/rdf/rdf-service;1"].getService(Components.interfaces.nsIRDFService);
  90.     var sbs = Components.classes["@mozilla.org/intl/stringbundle;1"].getService(Components.interfaces.nsIStringBundleService);    
  91.     this._bundle = sbs.createBundle("chrome://forecastfox/locale/forecastfox.properties");
  92.     this._obs = Components.classes["@mozilla.org/observer-service;1"].getService(Components.interfaces.nsIObserverService);
  93.         
  94.     this._removeOldFiles();
  95.     
  96.     // get the rdf service and datasource
  97.     this._getRdf(false);
  98.     this.setCurrent(this._manager.getUTFPref("icons.current"));
  99.   },
  100.   
  101.   stop: function()
  102.   {
  103.     this._manager = null;
  104.     this._rdfserv = null;
  105.     this._ds = null;
  106.     this._bundle = null;
  107.     this._obs = null;
  108.   },
  109.   
  110.   getItemList: function(aCount)
  111.   {
  112.     var items = [];
  113.     
  114.     // get the container for all the icons
  115.     var root = ICONS_ROOT;
  116.     var ctr = Components.classes["@mozilla.org/rdf/container;1"].createInstance(Components.interfaces.nsIRDFContainer);
  117.     ctr.Init(this._ds, this._rdfserv.GetResource(root));
  118.     
  119.     //loop through and get each item
  120.     var els = ctr.GetElements();
  121.     while (els.hasMoreElements()) {
  122.       var el = els.getNext().QueryInterface(Components.interfaces.nsIRDFResource);
  123.       items.push(this.getItemForId(this._stripIconPrefix(el.Value)));
  124.     };
  125.     
  126.     // sort the items by name
  127.     var component = this;
  128.     items.sort(component._sortItems);
  129.     
  130.     aCount.value = items.length;
  131.     return items;
  132.   },
  133.   
  134.   getItemForId: function( aId )
  135.   {
  136.     if (this._hasIconPack(aId)) {
  137.       return this._createIconPack(aId);
  138.     } else {
  139.       this._manager.disk.recordMessage("ERROR: Could not retrieve icon pack "+aId+", reverting to default.\n");
  140.       this._manager.setUTFPref("icons.current", "default");
  141.       return this.getDefaultItem();
  142.     };
  143.   },
  144.   
  145.   getDefaultItem: function()
  146.   {
  147.     try {
  148.       return this._createIconPack("default");
  149.     } catch (e) {
  150.       this._getRdf(true);
  151.       this._manager.disk.recordError("ERROR: Failure in retrieving default icon pack. Reverting to default icon rdf.", e);
  152.       return Components.classes["@ensolis.com/forecastfox/icon-pack;1"].createInstance(Components.interfaces.ffIIconPack);
  153.     };
  154.   },
  155.   
  156.   installItem: function( aFile )
  157.   {
  158.     // Create and initialize the installer.
  159.     var installer = Components.classes["@ensolis.com/forecastfox/icon-installer;1"].createInstance(Components.interfaces.ffIIconInstaller);
  160.     installer.init(aFile);
  161.     
  162.     // Validate the file...
  163.     var err = installer.validate();
  164.     if (err.severity != ffIError.SEVERITY_INFO)
  165.       this._manager.disk.recordMessage("ERROR: " + err.toString());
  166.     
  167.     //not validated
  168.     if (!installer.validated) {
  169.       installer.destroy();
  170.       return false;
  171.     };
  172.     
  173.     //try install
  174.     var rv = false;
  175.     try {
  176.       rv = installer.performInstall();     
  177.     } catch(e) {
  178.       var err = e;
  179.       rv = false;
  180.     };
  181.     installer.destroy();
  182.           
  183.     //install success
  184.     if (rv) {
  185.       this._saveRdf();
  186.       this._obs.notifyObservers(this, "forecastfox:icons", "install");      
  187.       return true;
  188.     };
  189.       
  190.     //install failed
  191.     this._getRdf(false);         
  192.     this._manager.disk.recordError("ERROR: icon pack install error.", err);
  193.     return false;          
  194.   },
  195.   
  196.   uninstallItem: function( aId )
  197.   {
  198.     //get the file for the pack
  199.     var file = this._getTarget(aId, "jar");
  200.     file = this._manager.disk.get(file, ffIDisk.TYPE_ICONS);
  201.     
  202.     //Create and initialize the installer.
  203.     var installer = Components.classes["@ensolis.com/forecastfox/icon-installer;1"].createInstance(Components.interfaces.ffIIconInstaller);
  204.     installer.init(file);
  205.  
  206.     //try uninstall
  207.     var rv = false;
  208.     try {
  209.       rv = installer.performUninstall();     
  210.     } catch(e) {
  211.       var err = e;
  212.       rv = false;
  213.     };
  214.     installer.destroy();
  215.           
  216.     //uninstall success
  217.     if (rv) {
  218.       this._saveRdf();
  219.       this._obs.notifyObservers(this, "forecastfox:icons", "uninstall");            
  220.       return true;
  221.     };
  222.       
  223.     //install failed
  224.     this._getRdf(false);         
  225.     this._manager.disk.recordError("ERROR: icon pack uninstall error.", err);
  226.     return false;    
  227.   },
  228.   
  229.   setCurrent: function(aId)
  230.   {
  231.     this._current = this.getItemForId(aId);
  232.   },
  233.   
  234.   _sortItems: function(a, b)
  235.   {
  236.     if (a.name < b.name)
  237.       return -1;
  238.     else
  239.       return 1;
  240.   },
  241.   
  242.   _createIconPack: function( aId )
  243.   {
  244.     // get the icon packs information
  245.     var id = aId;
  246.     var jar = this._getTarget(aId, "jar");
  247.     var name = this._getTarget(aId, "name");
  248.     var website = this._getTarget(aId, "website");
  249.     var author = this._getTarget(aId, "author");
  250.     var version = this._getTarget(aId, "version");
  251.     var target = this._getTarget(aId, "target");
  252.     var smallHeight = this._getTarget(aId, "smallHeight");
  253.     var smallWidth = this._getTarget(aId, "smallWidth");
  254.     var largeHeight = this._getTarget(aId, "largeHeight");
  255.     var largeWidth = this._getTarget(aId, "largeWidth");
  256.     var exemptions = [];
  257.     
  258.     // get resources for the id and name
  259.     var idResource = this._rdfserv.GetResource(ICON_PREFIX + aId);
  260.     var resource = this._rdfserv.GetResource(IM_PREFIX + "exemption");
  261.     var els = this._ds.GetTargets(idResource, resource, true);
  262.     while (els.hasMoreElements()) {
  263.       var el = els.getNext().QueryInterface(Components.interfaces.nsIRDFResource);
  264.       exemptions.push(this._createIconInfo(el));
  265.     };
  266.     
  267.     // create and initialize the icon pack
  268.     var pack = Components.classes["@ensolis.com/forecastfox/icon-pack;1"].createInstance(Components.interfaces.ffIIconPack);
  269.     pack.init(id, jar, name, website, author, version, target, smallHeight, smallWidth, largeHeight, largeWidth, exemptions.length, exemptions);
  270.     
  271.     // return the pack
  272.     return pack;
  273.   },
  274.   
  275.   _createIconInfo: function( aSource )
  276.   {
  277.     // get the info for the exemption
  278.     var index = this._getSourceTarget(aSource, "index");
  279.     var size = this._getSourceTarget(aSource, "size");
  280.     var width = this._getSourceTarget(aSource, "width");
  281.     var height = this._getSourceTarget(aSource, "height");
  282.     
  283.     // create and initialize the info object
  284.     var iconInfo = Components.classes["@ensolis.com/forecastfox/icon-info;1"].createInstance(Components.interfaces.ffIIconInfo);
  285.     iconInfo.init("", width, height, (size == "large"), index);
  286.     
  287.     return iconInfo;
  288.   },
  289.   
  290.   _getSourceTarget: function( aSource, aName )
  291.   {
  292.     // get resources for the id and name
  293.     var nameResource = this._rdfserv.GetResource(IM_PREFIX + aName);
  294.     
  295.     return this._evalTarget(aSource, nameResource);
  296.   },
  297.   
  298.   _getTarget: function( aId, aName )
  299.   {
  300.     // get resources for the id and name
  301.     var nameResource = this._rdfserv.GetResource(IM_PREFIX + aName);
  302.     var idResource = this._rdfserv.GetResource(ICON_PREFIX + aId);
  303.     
  304.     return this._evalTarget(idResource, nameResource);
  305.   },
  306.   
  307.   _evalTarget: function( aSource, aProperty )
  308.   {
  309.     // get the target resource and then return its value
  310.     var target = this._ds.GetTarget(aSource, aProperty, true);
  311.     return this._getTargetValue(target);
  312.   },
  313.   
  314.   _getTargetValue: function(aTarget)
  315.   {
  316.     if (aTarget instanceof Components.interfaces.nsIRDFLiteral)
  317.       return aTarget.Value;
  318.     if (aTarget instanceof Components.interfaces.nsIRDFResource)
  319.       return aTarget.Value;
  320.     if (aTarget instanceof Components.interfaces.nsIRDFInt)
  321.       return aTarget.Value;
  322.     
  323.     return "undefined";
  324.   },
  325.   
  326.   _hasIconPack: function(aId)
  327.   {
  328.     // get the container for all the icons
  329.     var root = ICONS_ROOT;
  330.     var ctr = Components.classes["@mozilla.org/rdf/container;1"].createInstance(Components.interfaces.nsIRDFContainer);
  331.     ctr.Init(this._ds, this._rdfserv.GetResource(root));
  332.     
  333.     var iconNode = this._rdfserv.GetResource(ICON_PREFIX+aId);
  334.     
  335.     return (ctr.IndexOf(iconNode) > 0);
  336.   },
  337.   
  338.   _getRdf: function(aRevert)
  339.   {
  340.     //unregister datasource
  341.     if (aRevert && this._ds)
  342.       this._rdfserv.UnregisterDataSource(this._ds);
  343.         
  344.     // get the datasource.rdf file
  345.     var file = this._manager.disk.get("datasource.rdf", ffIDisk.TYPE_ICONS);
  346.     
  347.     // get the one from defaults if this one doesn't exist
  348.     if (!file.exists() || aRevert) {
  349.       this._getDefaultRdf();
  350.     } else if (!file.isWritable() || !file.isReadable()) {
  351.       // the file needs to be readable and writable
  352.       this._readWriteError(file);
  353.       this._manager.disk.recordMessage("Warning: The datasource.rdf file is not writable: "+file.path);
  354.       return;
  355.     } else {
  356.       file = this._manager.disk.getFileURI(file);        
  357.       this._ds = this._rdfserv.GetDataSourceBlocking(file);    
  358.       this._verifyRdf();     
  359.     };
  360.   },
  361.   
  362.   _verifyRdf: function()
  363.   {
  364.     try {
  365.       var defaultPack = this.getItemForId("default");
  366.       if (defaultPack.id != "default")
  367.         throw "Can't get default pack from RDF datasource.";
  368.     } catch (e) {
  369.       this._manager.disk.recordError("ERROR: Icon datasource is corrupted.", e);
  370.       this._manager.disk.recordFile(this._manager.disk.get("datasource.rdf", ffIDisk.TYPE_ICONS));
  371.       this._getRdf(true);
  372.     };
  373.   },
  374.   
  375.   _getDefaultRdf: function ()
  376.   {
  377.     //create content string of file
  378.     var contents = new String();
  379.     contents += '<?xml version="1.0"?>\n' + 
  380.                 '<RDF xmlns="http://www.w3.org/1999/02/22-rdf-syntax-ns#"\n' +
  381.                 '     xmlns:NC="http://home.netscape.com/NC-rdf#"\n' +
  382.                 '     xmlns:im="http://www.ensolis.com/2005/icon-manager#">\n' +
  383.                 '  <Seq about="urn:ensolis:icon-packs:root">\n' +
  384.                 '  </Seq>\n' +
  385.                 '</RDF>\n'
  386.     
  387.     //convert to dom document
  388.     var parser = Components.classes["@mozilla.org/xmlextras/domparser;1"].createInstance(Components.interfaces.nsIDOMParser);       
  389.     var doc = parser.parseFromString(contents, "text/xml");
  390.     
  391.     //write to file
  392.     var file = this._manager.disk.get("datasource.rdf", ffIDisk.TYPE_ICONS);
  393.     this._manager.disk.write(doc, file, false);
  394.     file = this._manager.disk.getFileURI(file);        
  395.       
  396.     //load file as datasource
  397.     this._ds = this._rdfserv.GetDataSourceBlocking(file);
  398.     
  399.     //install default icons
  400.     var pack = this._manager.disk.get("icons", ffIDisk.TYPE_DEFAULTS);
  401.     pack.append("default.jar");
  402.     this.installItem(pack);         
  403.   },
  404.   
  405.   // Records the datasource to disk.
  406.   _saveRdf: function()
  407.   {
  408.     this._ds.QueryInterface(Components.interfaces.nsIRDFRemoteDataSource).Flush();
  409.   },
  410.     
  411.   _readWriteError: function( aFile )
  412.   {
  413.     var alerts = Components.classes["@mozilla.org/embedcomp/prompt-service;1"].getService(Components.interfaces.nsIPromptService);
  414.     var err_msg = this._bundle.formatStringFromName("ff.migrate.read.tooltip", [aFile.path], 1);
  415.     var err_title = this._bundle.GetStringFromName("ff.migrate.read.label");
  416.     alerts.alert(this._manager.getWindow(), err_title, err_msg);
  417.   },
  418.   
  419.   _stripIconPrefix: function (aURI)
  420.   {
  421.     var prefix = ICON_PREFIX;
  422.     var value = aURI;
  423.     
  424.     if (aURI.substr(0, prefix.length) == prefix)
  425.       value = aURI.substr(prefix.length, aURI.length);
  426.     
  427.     return value;
  428.   },
  429.   
  430.   _removeOldFiles: function()
  431.   {
  432.     var files = this._manager.getUTFPref("icons.uninstallfiles");
  433.     if (files == "") return;
  434.     
  435.     var base = this._manager.disk.get("", ffIDisk.TYPE_ICONS);
  436.     files = files.split(";");
  437.     
  438.     for (var x = 0; x < files.length; x++) {
  439.       var file = base.clone();
  440.       file.append(files[x]);
  441.       if (file.exists() && file.isWritable()) {
  442.         file.remove(false);
  443.       };
  444.     };
  445.     
  446.     this._manager.setUTFPref("icons.uninstallfiles", "");
  447.   },
  448.     
  449.   ///////////////////////////
  450.   // nsIClassInfo  
  451.   getInterfaces: function(aCount)
  452.   {
  453.     var ifaces = new Array();
  454.     ifaces.push(Components.interfaces.ffIIconManager);
  455.     ifaces.push(Components.interfaces.nsIClassInfo);
  456.     ifaces.push(Components.interfaces.nsISupports);
  457.     aCount.value = ifaces.length;
  458.     return ifaces;
  459.   },
  460.   
  461.   getHelperForLanguage: function(aLanguage) { return null; },
  462.   get contractID() { return CONTRACT_ID; },
  463.   get classID() { return CLASS_ID; },
  464.   get classDescription() { return CLASS_NAME; },
  465.   get implementationLanguage() { return Components.interfaces.nsIProgrammingLanguage.JAVASCRIPT; },
  466.   get flags() { return Components.interfaces.nsIClassInfo.SINGLETON; },
  467.   
  468.   ///////////////////////////
  469.   // nsISupports
  470.   QueryInterface: function (aIID)
  471.   {
  472.     if (!aIID.equals(Components.interfaces.ffIIconManager) &&
  473.         !aIID.equals(Components.interfaces.nsIClassInfo) &&      
  474.         !aIID.equals(Components.interfaces.nsISupports))
  475.       throw Components.results.NS_ERROR_NO_INTERFACE;
  476.     return this;
  477.   }
  478. };
  479.  
  480. /******************************************************************************
  481.  * ffIIconInstaller
  482.  ******************************************************************************/
  483.  
  484. function ffIconInstaller() {};
  485.  
  486. ffIconInstaller.prototype = {
  487.   
  488.   _manager: null,
  489.   _file: null,
  490.   _rdfserv: null,
  491.   _ds: null,
  492.   _validated: false,
  493.   _manifest: null,
  494.   _files: null,
  495.   _reader: null,
  496.   _bundle: null,
  497.   _temp: null,
  498.   
  499.   get validated() { return this._validated; },
  500.   
  501.   init: function( aFile )
  502.   {
  503.     // Get services...
  504.     this._manager = Components.classes["@ensolis.com/forecastfox/manager;1"].getService(Components.interfaces.ffIManager);
  505.     this._rdfserv = Components.classes["@mozilla.org/rdf/rdf-service;1"].getService(Components.interfaces.nsIRDFService);
  506.     var sbs = Components.classes["@mozilla.org/intl/stringbundle;1"].getService(Components.interfaces.nsIStringBundleService);    
  507.     this._bundle = sbs.createBundle("chrome://forecastfox/locale/forecastfox.properties");
  508.     this._ctrutils = Components.classes["@mozilla.org/rdf/container-utils;1"].createInstance(Components.interfaces.nsIRDFContainerUtils);
  509.     
  510.     // Record parameters...
  511.     this._file = aFile.clone();
  512.     this._ds = this._manager.icons.datasource;
  513.     this._files = [];
  514.     
  515.     // Prepare the nsIZipReader...
  516.     this._reader = Components.classes["@mozilla.org/libjar/zip-reader;1"].createInstance(Components.interfaces.nsIZipReader);
  517.     this._reader.init(this._file);
  518.     this._reader.open();
  519.     
  520.     // Get a list of all the files...
  521.     this._populateFileList();
  522.   },
  523.   
  524.   destroy: function()
  525.   {
  526.     this._reader.close();
  527.     
  528.     try {
  529.       if (this._temp)
  530.         this._temp.remove(false);
  531.     } catch(e) {};
  532.     
  533.     this._manager = null;
  534.     this._bundle = null;
  535.     this._rdfserv = null;
  536.     this._file = null;
  537.     this._ds = null;
  538.     this._manifest = null;
  539.     this._files = null;
  540.     this._reader = null;
  541.     this._ctrutils = null;
  542.     this._temp = null;
  543.   },
  544.   
  545.   validate: function()
  546.   {
  547.     this._getManifest();
  548.     
  549.     // Throw an error if there is no manifest.
  550.     if (!this._validateManifest())
  551.       return this._createError(ffIError.SEVERITY_ERROR, null, "ff.icons.manifest");
  552.     
  553.     // Make sure we have all the required files.
  554.     var err = this._validateRequiredFiles();
  555.     if (err.severity != ffIError.SEVERITY_INFO)
  556.       return err;
  557.     
  558.     // Mark as validated so that the install can be executed.
  559.     this._validated = true;
  560.     
  561.     // Return a SEVERITY_INFO since the jar is good (the message won't be displayed).
  562.     return this._createError(ffIError.SEVERITY_INFO, "all good");
  563.   },
  564.   
  565.   performInstall: function()
  566.   {
  567.     // You must validate before performing an install.
  568.     if (!this._validated)
  569.       return false;
  570.     
  571.     this._getId();
  572.     
  573.     // Copy the icon pack jar to the correct location.
  574.     if (!this._copyPack())
  575.       return false;
  576.     
  577.     // Register the icon pack in the rdf datasource.
  578.     return this._registerPack();
  579.   },
  580.   
  581.   performUninstall: function()
  582.   {
  583.     // Initialize the icon pack container in the main datasource.
  584.     var ctr = Components.classes["@mozilla.org/rdf/container;1"].createInstance(Components.interfaces.nsIRDFContainer);
  585.     ctr.Init(this._ds, this._rdfserv.GetResource(ICONS_ROOT));
  586.     
  587.     //get the id of the pack
  588.     this._getManifest();    
  589.     this._getId();
  590.         
  591.     //unregister the pack.
  592.     var id = this._rdfserv.GetResource(ICON_PREFIX + this._id);
  593.     if (ctr.IndexOf(id) >= 0)
  594.       this._unregisterPack(id, ctr);
  595.     else
  596.       return false;
  597.      
  598.     //success       
  599.     return true;
  600.   },
  601.   
  602.   // Gets and returns the datasource representing the file object that is in the 
  603.   _getManifest: function()
  604.   {
  605.     // Verify that we have a pack.rdf in the icon pack.
  606.     if (!this._hasFile("pack.rdf"))
  607.       this._manifest = false;
  608.     
  609.     // Get a temp file to store the pack.rdf in.
  610.     this._temp = this._manager.disk.get("icon-pack.rdf", ffIDisk.TYPE_TEMP);
  611.     
  612.     // Extract the file and get the datasource object for it...
  613.     this._reader.extract("pack.rdf", this._temp);
  614.     this._manifest = this._rdfserv.GetDataSourceBlocking(this._manager.disk.getFileURI(this._temp));
  615.   },
  616.   
  617.   _validateManifest: function()
  618.   {
  619.     // Fail if there is no manifest.
  620.     if (!this._manifest)
  621.       return false;
  622.     
  623.     var source = this._rdfserv.GetResource(ICON_PREFIX+"install");
  624.     
  625.     // Check for the required properties...
  626.     for (var x = 0; x < REQUIRED_ICON_PROPS.length; x++) {
  627.       var resource = this._rdfserv.GetResource(IM_PREFIX + REQUIRED_ICON_PROPS[x]);
  628.       if (!this._manifest.hasArcOut(source, resource)) {
  629.         return false;
  630.       };
  631.     };
  632.     
  633.     return true;
  634.   },
  635.   
  636.   _validateRequiredFiles: function()
  637.   {
  638.     var required = REQUIRED_PACK_FILES;
  639.     
  640.     // Make sure every required file can be found in the icon pack.
  641.     for (var x = 0; x < required.length; x++) {
  642.       var found = false;
  643.       for (var y = 0; y < this._files.length; y++) {
  644.         if (required[x] == this._files[y]) {
  645.           found = true;
  646.           break;
  647.         };
  648.       };
  649.       
  650.       // Don't return an error if the file has been found.
  651.       if (found) continue;
  652.       
  653.       return this._createError(ffIError.SEVERITY_ERROR, this._getFileString(required[x]));
  654.     };
  655.     
  656.     // All files present... 
  657.     return this._createError(ffIError.SEVERITY_INFO, "required files are present"); // message not displayed
  658.   },
  659.   
  660.   _copyPack: function()
  661.   {
  662.     // remove ";" characters from name so that the uninstall works
  663.     var file = this._manager.disk.get(this._id.replace(";", "") + ".jar", ffIDisk.TYPE_ICONS);
  664.     
  665.     file.createUnique(nsIFile.NORMAL_FILE_TYPE, 0664);
  666.     
  667.     this._jar = file.leafName;
  668.     
  669.     this._manager.disk.copy(this._file, file);
  670.     
  671.     return true;
  672.   },
  673.   
  674.   _registerPack: function()
  675.   {
  676.     // Initialize the icon pack container in the main datasource.
  677.     var ctr = Components.classes["@mozilla.org/rdf/container;1"].createInstance(Components.interfaces.nsIRDFContainer);
  678.     ctr.Init(this._ds, this._rdfserv.GetResource(ICONS_ROOT));
  679.     
  680.     // If it is an upgrade, first unregister the old pack.
  681.     var id = this._rdfserv.GetResource(ICON_PREFIX + this._id);
  682.     if (ctr.IndexOf(id) >= 0)
  683.       this._unregisterPack(id, ctr);
  684.     
  685.     // Insert the new node.
  686.     ctr.AppendElement(id);
  687.     var jar = this._rdfserv.GetResource(IM_PREFIX + "jar");
  688.     var jarlit = this._rdfserv.GetLiteral(this._jar);
  689.     this._ds.Assert(id, jar, jarlit, true);
  690.     
  691.     
  692.     // Copy the required properties.
  693.     var source = this._rdfserv.GetResource(ICON_PREFIX + "install");        
  694.     for (var i=0; i<REQUIRED_ICON_PROPS.length; ++i) {
  695.       var resource = this._rdfserv.GetResource(IM_PREFIX + REQUIRED_ICON_PROPS[i]);
  696.       this._setProperty(id, source, resource);
  697.     };
  698.     
  699.     // Copy the optional properties
  700.     var index = this._rdfserv.GetResource(IM_PREFIX + "index");
  701.     var size = this._rdfserv.GetResource(IM_PREFIX + "size");
  702.     var width = this._rdfserv.GetResource(IM_PREFIX + "width");
  703.     var height = this._rdfserv.GetResource(IM_PREFIX + "height");
  704.     var resource = this._rdfserv.GetResource(IM_PREFIX + "exemption");
  705.     var els = this._manifest.GetTargets(source, resource, true);
  706.     while (els.hasMoreElements()) {
  707.       var el = els.getNext().QueryInterface(Components.interfaces.nsIRDFResource);
  708.       var anon = this._rdfserv.GetAnonymousResource();
  709.       this._ds.Assert(anon, index, this._manifest.GetTarget(el, index, true), true);
  710.       this._ds.Assert(anon, size, this._manifest.GetTarget(el, size, true), true);
  711.       this._ds.Assert(anon, width, this._manifest.GetTarget(el, width, true), true);
  712.       this._ds.Assert(anon, height, this._manifest.GetTarget(el, height, true), true);
  713.       this._ds.Assert(id, resource, anon, true);
  714.     };    
  715.     
  716.     // Success!
  717.     return true;
  718.   },
  719.   
  720.   _unregisterPack: function(aIdResource, aContainer)
  721.   {
  722.     //remove jar
  723.     var jar = this._rdfserv.GetResource(IM_PREFIX + "jar");
  724.     jar = this._ds.GetTarget(aIdResource, jar, true);
  725.     jar = jar.QueryInterface(Components.interfaces.nsIRDFLiteral);
  726.     jar = this._manager.disk.get(jar.Value, ffIDisk.TYPE_ICONS);
  727.     if (jar.exists())
  728.       this._delayRemove(jar);
  729.       
  730.     //remove exemptions
  731.     var els = this._ds.GetTargets(aIdResource, this._rdfserv.GetResource(IM_PREFIX + "exemption"), true);
  732.     while (els.hasMoreElements()) {
  733.       var el = els.getNext().QueryInterface(Components.interfaces.nsIRDFResource);
  734.       this._cleanResource(el);
  735.     };
  736.  
  737.     //remove item
  738.     this._cleanResource(aIdResource);
  739.     aContainer.RemoveElement(aIdResource, true);
  740.   },
  741.   
  742.   _delayRemove: function ( /* nsIFile */ aFile )
  743.   {
  744.     var file = aFile.leafName;
  745.     var files = this._manager.getUTFPref("icons.uninstallfiles");
  746.     
  747.     // want: file1.jar or file1.jar;file2.jar;file3.jar
  748.     files = ((files != "") ? files + ";" : "") + file;
  749.     
  750.     this._manager.setUTFPref("icons.uninstallfiles", files);
  751.   },
  752.   
  753.   _cleanResource: function(aIdResource)
  754.   {    
  755.     // Remove outward arcs
  756.     var arcs = this._ds.ArcLabelsOut(aIdResource);
  757.     while (arcs.hasMoreElements()) {
  758.       var arc = arcs.getNext().QueryInterface(Components.interfaces.nsIRDFResource);
  759.       var targets = this._ds.GetTargets(aIdResource, arc, true);      
  760.       while (targets.hasMoreElements()) {
  761.         var value = targets.getNext().QueryInterface(Components.interfaces.nsIRDFNode);
  762.         if (value)
  763.           this._ds.Unassert(aIdResource, arc, value);
  764.       };
  765.     };
  766.   },
  767.  
  768.   _setProperty: function( aNode, aSource, aTarget )
  769.   {          
  770.     var value = this._manifest.GetTarget(aSource, aTarget, true);
  771.     this._ds.Assert(aNode, aTarget, value, true);
  772.   },
  773.     
  774.   _populateFileList: function()
  775.   {
  776.     var entries = this._reader.findEntries("*");
  777.     
  778.     while (entries.hasMoreElements()) {
  779.       var entry = entries.getNext().QueryInterface(Components.interfaces.nsIZipEntry);
  780.       this._files.push(entry.name);
  781.     };
  782.   },
  783.   
  784.   _hasFile: function( aFileName )
  785.   {
  786.     for (var x = 0; x < this._files.length; x++) {
  787.       if (this._files[x] == aFileName)
  788.         return true;
  789.     };
  790.     
  791.     return false;
  792.   },
  793.   
  794.   _createError: function( aSeverity, aDescription, aString )
  795.   {
  796.     var description = (aDescription) ? aDescription : this._bundle.GetStringFromName(aString);
  797.     var title = this._bundle.GetStringFromName("ff.icons.invalid");
  798.     var error = Components.classes["@ensolis.com/forecastfox/error;1"].createInstance(Components.interfaces.ffIError);
  799.     error.init(aSeverity, "@ensolis.com/forecastfox/profiles;1", description, title); 
  800.     return error;
  801.   },
  802.   
  803.   _getFileString: function( aFile )
  804.   {
  805.     return this._bundle.formatStringFromName("ff.icons.file", [aFile], 1);
  806.   },
  807.   
  808.   _getId: function()
  809.   {
  810.     var source = this._rdfserv.GetResource(ICON_PREFIX + "install");
  811.     var id = this._rdfserv.GetResource(IM_PREFIX + "id");
  812.     id = this._manifest.GetTarget(source, id, true);
  813.     id = id.QueryInterface(Components.interfaces.nsIRDFLiteral);
  814.     this._id = id.Value;
  815.   },
  816.   
  817.   ///////////////////////////
  818.   // nsIClassInfo  
  819.   getInterfaces: function(aCount)
  820.   {
  821.     var ifaces = new Array();
  822.     ifaces.push(Components.interfaces.ffIIconInstaller);
  823.     ifaces.push(Components.interfaces.nsIClassInfo);
  824.     ifaces.push(Components.interfaces.nsISupports);
  825.     aCount.value = ifaces.length;
  826.     return ifaces;
  827.   },
  828.   
  829.   getHelperForLanguage: function(aLanguage) { return null; },
  830.   get contractID() { return INSTALLER_CONTRACT_ID; },
  831.   get classID() { return INSTALLER_CLASS_ID; },
  832.   get classDescription() { return INSTALLER_CLASS_NAME; },
  833.   get implementationLanguage() { return Components.interfaces.nsIProgrammingLanguage.JAVASCRIPT; },
  834.   get flags() { return Components.interfaces.nsIClassInfo.THREADSAFE; },
  835.   
  836.   ///////////////////////////
  837.   // nsISupports
  838.   QueryInterface: function (aIID)
  839.   {
  840.     if (!aIID.equals(Components.interfaces.ffIIconInstaller) &&
  841.         !aIID.equals(Components.interfaces.nsIClassInfo) &&      
  842.         !aIID.equals(Components.interfaces.nsISupports))
  843.       throw Components.results.NS_ERROR_NO_INTERFACE;
  844.     return this;
  845.   }
  846. };
  847.  
  848. /******************************************************************************
  849.  * XPCOM Functions for construction and registration
  850.  ******************************************************************************/
  851. var gModule = {
  852.   _firstTime: true,
  853.   _objects: {
  854.     iconManager: {
  855.       CID: MANAGER_CLASS_ID,
  856.       contractID: MANAGER_CONTRACT_ID,
  857.       className: MANAGER_CLASS_NAME,
  858.       factory: {
  859.         createInstance: function (aOuter, aIID)
  860.         {
  861.           if (aOuter != null)
  862.             throw Components.results.NS_ERROR_NO_AGGREGATION;
  863.           return (new ffIconManager()).QueryInterface(aIID);
  864.         }
  865.       }
  866.     },
  867.     
  868.     iconInstaller: {
  869.       CID: INSTALLER_CLASS_ID,
  870.       contractID: INSTALLER_CONTRACT_ID,
  871.       className: INSTALLER_CLASS_NAME,
  872.       factory: {
  873.         createInstance: function (aOuter, aIID)
  874.         {
  875.           if (aOuter != null)
  876.             throw Components.results.NS_ERROR_NO_AGGREGATION;
  877.           return (new ffIconInstaller()).QueryInterface(aIID);
  878.         }
  879.       }
  880.     }
  881.   },
  882.   
  883.   registerSelf: function(aCompMgr, aFileSpec, aLocation, aType)
  884.   {
  885.     if (this._firstTime) {
  886.       this._firstTime = false;
  887.       throw Components.results.NS_ERROR_FACTORY_REGISTER_AGAIN;
  888.     };
  889.     aCompMgr = aCompMgr.QueryInterface(Components.interfaces.nsIComponentRegistrar);
  890.     for (var key in this._objects) {
  891.       var obj = this._objects[key];
  892.       aCompMgr.registerFactoryLocation(obj.CID, obj.className, obj.contractID,
  893.                                        aFileSpec, aLocation, aType);
  894.     };
  895.   },
  896.   
  897.   unregisterSelf: function(aCompMgr, aLocation, aType)
  898.   {
  899.     aCompMgr = aCompMgr.QueryInterface(Components.interfaces.nsIComponentRegistrar);
  900.     for (var key in this._objects) {
  901.       var obj = this._objects[key];
  902.       aCompMgr.unregisterFactoryLocation(obj.CID, aLocation);
  903.     };
  904.   },
  905.   
  906.   getClassObject: function(aCompMgr, aCID, aIID)
  907.   {
  908.     if (!aIID.equals(Components.interfaces.nsIFactory))
  909.       throw Components.results.NS_ERROR_NOT_IMPLEMENTED;
  910.  
  911.     for (var key in this._objects) {
  912.       if (aCID.equals(this._objects[key].CID))
  913.         return this._objects[key].factory;
  914.     };
  915.  
  916.     throw Components.results.NS_ERROR_NO_INTERFACE;
  917.   },
  918.  
  919.   canUnload: function(aCompMgr) { return true; }
  920. };
  921.  
  922. var gFactory = {
  923.   createInstance: function (aOuter, aIID)
  924.   {
  925.     if (aOuter != null)
  926.       throw Components.results.NS_ERROR_NO_AGGREGATION;
  927.     return (new ffIconManager()).QueryInterface(aIID);
  928.   }
  929. };
  930.  
  931. function NSGetModule(aCompMgr, aFileSpec) { return gModule; }